package imageEditor.mapEditor;

import imageEditor.mapEditor.model.Map;
import imageEditor.utility.ImageDatabase;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class MapEditor implements ListSelectionListener, ActionListener {
	public static void main(String[] args) {
		new MapEditor();
	}
	
	private JFrame frame;
	private Container mainContainer;
	private MapPainer center;
	private JList list;
	private ImageDatabase db;
	private ArrayList<Integer> ids;
	private HashMap<Integer, Map> maps;
	private JButton addMap;
	private DefaultListModel listModel;
	private JMenuItem saveMenu;
	private JMenuItem exportMenu;
	private JMenuItem loadMenu;
	private JPanel west;
	
	
	public MapEditor(){
		frame=new JFrame("Map Editor");
		mainContainer=frame.getContentPane();
		mainContainer.setLayout(new BorderLayout());
		
		db=new ImageDatabase(null);
		ids=new ArrayList<Integer>();
		maps=new HashMap<Integer, Map>();
		
		buildMenu();
		buildWest();
		
		center=new MapPainer();
		mainContainer.add(center,"Center");
		
		
		frame.setSize(800, 600);
		frame.setVisible(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	private void buildMenu(){
		JMenuBar menu=new JMenuBar();
		
		JMenu fileMenu=new JMenu("File");
		menu.add(fileMenu);
		
		saveMenu=new JMenuItem("save");
		saveMenu.addActionListener(this);
		fileMenu.add(saveMenu);
		
		loadMenu=new JMenuItem("load");
		loadMenu.addActionListener(this);
		fileMenu.add(loadMenu);
		
		exportMenu=new JMenuItem("export");
		exportMenu.addActionListener(this);
		fileMenu.add(exportMenu);
		
		frame.setJMenuBar(menu);		
	}
	
	private void buildWest(){
		if(west!=null)
			mainContainer.remove(west);
		
		listModel = new DefaultListModel();
		
		for(int id:db.getId()){
			listModel.addElement("map "+id);
			ids.add(id);
		}
		
		list=new JList(listModel);
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.setLayoutOrientation(JList.VERTICAL);
		list.setVisibleRowCount(-1);
		list.addListSelectionListener(this);
		
		JScrollPane listPanel=new JScrollPane(list);
		
		west=new JPanel();
		west.setLayout(new BorderLayout());
		
		west.add(listPanel,"Center");
		
		addMap=new JButton("add map");
		addMap.addActionListener(this);
		
		west.add(addMap,"South");
		

		mainContainer.add(west,"West");
	}

	public void valueChanged(ListSelectionEvent e) {
		if(!e.getValueIsAdjusting()){
			int index=list.getSelectedIndex();
			if(index!=-1){
				int id=ids.get(index);
				
				if(!maps.containsKey(id))
					return;
				
				Map current=maps.get(id);
				center.setMap(current);
			}
		}
	}

	public void actionPerformed(ActionEvent e) {
		Object source=e.getSource();
		
		if(source==addMap){
			String s=(String)JOptionPane.showInputDialog(
					frame,
					"Set the map id of the destiantion",
					"Destinatio id",
					JOptionPane.PLAIN_MESSAGE,
					null,
					null,
					"");
			
			JFileChooser fc = new JFileChooser();
			
			int returnVal = fc.showOpenDialog(frame);
			
			if (returnVal == JFileChooser.APPROVE_OPTION){
				File file=fc.getSelectedFile();
				
				try {
					int id=Integer.parseInt(s);
					db.addImage(file, id);
					maps.put(id,new Map(db.getMap(id), id, "", db.getSize(id)));
					
					listModel.addElement("map "+id);
					ids.add(id);
					
					frame.repaint();
					frame.validate();
				}
				catch (Exception e1) {e1.printStackTrace();}
			}
		}
		else if(source==exportMenu){
			try {
				db.save("maps");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			
			createMapsDefintion();
			
			JOptionPane.showMessageDialog(frame, "maps and MapsDefinition.java exported", "Export done!", JOptionPane.INFORMATION_MESSAGE);
		}
		else if(source==saveMenu){
			JFileChooser fc = new JFileChooser();
			
			int returnVal = fc.showSaveDialog(frame);
			
			if (returnVal == JFileChooser.APPROVE_OPTION){
				try{
					File file=fc.getSelectedFile();
					FileOutputStream fos = new FileOutputStream(file);
					ObjectOutputStream oos = new ObjectOutputStream(fos);
					oos.writeObject(maps);
					oos.close();
					
					JOptionPane.showMessageDialog(frame, "project saved on "+file.getAbsolutePath(), "Saved!", JOptionPane.INFORMATION_MESSAGE);
				}catch(Exception ex){ex.printStackTrace();}
			}
		}
		else if(source==loadMenu){
			JFileChooser fc = new JFileChooser();
			
			int returnVal = fc.showOpenDialog(frame);
			
			if (returnVal == JFileChooser.APPROVE_OPTION){
				File file=fc.getSelectedFile();
				
				try {
					FileInputStream fis = new FileInputStream(file);
					ObjectInputStream iis = new ObjectInputStream(fis);
					maps = (HashMap<Integer, Map>) iis.readObject();
					iis.close();
					
					db=new ImageDatabase(null);
					ids=new ArrayList<Integer>();
					
					for(int key:maps.keySet()){
						Map m=maps.get(key);
						db.addImage(m.getImageInt(), key,m.getWidth(), m.getHeight());
					}
					
					buildWest();
					
					frame.repaint();
					frame.validate();
				}
				catch (Exception e1) {e1.printStackTrace();}
			}
		}
	}

	private void createMapsDefintion() {
		String content=
			"package server.map;\n\n"+

			"import server.main.Data;\n"+
			"import server.utility.Id;\n"+
			"import server.utility.Point2d;\n\n"+

			"public class MapsDefinition {\n\n"+
			
			"\tpublic static void loadMaps(){\n";
			
			content+="\t\tinternal();\n";
			for(int id:db.getId())
				content+="\t\tmap"+id+"();\n";
			
			content+="\t}\n\n";
			
			content+=
				"\tprivate static void internal(){\n"+
				"\t\tMap internal = new Map(new Point2d(),new Point2d(), \"Internal\", new Id(-1));\n"+
				"\t\tData.add(internal);\n"+
				"\t}\n\n";
			
			for(int id:maps.keySet()){
				Map m=maps.get(id);
				content+=
					"\tprivate static void map"+id+"(){\n"+
					m.getCode()+"\n"+
					"\t\tData.add(map)\n"+
					"\t}\n\n";
			}
			
			content+="}";
			
			File file=new File("MapsDefinition.java");
			
			try{
				BufferedWriter out=new BufferedWriter(new FileWriter(file));
				out.write(content);
				out.close();
			}catch(Exception ex){ex.printStackTrace();}
	}

}
